﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Media3D;
using HelixToolkit.Wpf;
using System.Runtime.Serialization;
using System.IO;

namespace GameBoard
{
    [DataContract(Namespace = "")]
    public class MoveablePicture : INotifyPropertyChanged
    {
        private CharacterImagePiece _charImage;
        public CharacterImagePiece CharImage
        {
            get { return _charImage; }
            set { _charImage = value; }
        }

        private TruncatedConeVisual3D _baseCone;
        public TruncatedConeVisual3D BaseCone
        {
            get { return _baseCone; }
            set { _baseCone = value; }
        }
        private List<int> _movementCirclesRadiusList;
        [DataMember]
        public List<int> MovementCirclesRadiusList
        {
            get { return _movementCirclesRadiusList; }
            set { _movementCirclesRadiusList = value; }
        }

        public List<Visual3D> _movementCircles = new List<Visual3D>();
        public List<Visual3D> MovementCircles
        {
            get
            {
                return _movementCircles;
            }
            set
            {
                _movementCircles = value;
            }
        }

        public String AdditionalDisplayText { get; set; }

        public BillboardTextVisual3D InfoText
        { get; set; }

        private List<Visual3D> _associatedVisuals = new List<Visual3D>();
        public IEnumerable<Visual3D> AssociatedVisuals
        {
            get 
            {
                foreach (var cur in MovementCircles)
                {
                    yield return cur;
                }
                yield return InfoText;
            }
        }
        

        private double _pictureOffset;
        [DataMember]
        public double PictureOffset
        {
            get { return _pictureOffset; }
            set { _pictureOffset = value; }
        }
        private String _name;
        [DataMember]
        public String Name
        {
            get { return _name; }
            set { _name = value; }
        }

        [DataMember]
        public double Speed { get; set; }
        [DataMember]
        public Color PieceColor { get; set; }

        [DataMember]
        public double LongestPictureSide { get; set; }

        public Point3D Location
        {
            get { return CharImage.Origin; }
            set
            {
                LocationForSave = value;
                MoveTo(value);
            }
        }
        [DataMember]
        public Point3D LocationForSave
        {get;set;}

        public double BaseConeRadius { get; set; }
        private bool _isSelected;
        public bool IsSelected
        {
            get { return _isSelected; }
            set 
            {
                _isSelected = value;
                bool onlyOneSelected = VisualsService.BoardsViewModel.MainBoard.VisualsViewModel.NumberActive == 1;

                if (_isSelected)
                {
                    StartActive(onlyOneSelected);
                }
                else
                    StopActive();
                OnPropertyChanged("IsSelected");
            }
        }

        private string _pictureFileName = "";
        [DataMember]
        public String PictureFileName 
        {
            get { return _pictureFileName;}
            set { _pictureFileName = value;}
        }

        public String PictureFileAbsolutePath
        {
            get
            {
                return Directory.GetCurrentDirectory() + "\\" + _pictureFileName;
            }
        }

        private List<StatusEffectDisplay> _statusEffects = new List<StatusEffectDisplay>();
        [DataMember]
        public List<StatusEffectDisplay> StatusEffects
        {
            get { return _statusEffects; }
            set { _statusEffects = value; }
        }
        public MoveablePicture(String pictureFile, 
            double longestEdge, String imageName,
            Color pieceColor,
            Point3D location,
            List<StatusEffectDisplay> statuses, 
            double speed,
            List<int> movementCircleRadiusList
            )
        {
            MovementCirclesRadiusList = movementCircleRadiusList;
            PieceColor = pieceColor;
            Name = imageName;
            Speed = speed;
            LocationForSave = location;
            PictureFileName = pictureFile;
            _charImage = ImageToRectangle(pictureFile, longestEdge, location, movementCircleRadiusList);
            LongestPictureSide = longestEdge;
            RemakeInfoText(statuses);
            StatusEffects = statuses;

        }

        [OnDeserialized]
        public void OnDeserialized(StreamingContext context)
        {
            _movementCircles = new List<Visual3D>();
            _associatedVisuals = new List<Visual3D>();
            _charImage = ImageToRectangle(PictureFileName, LongestPictureSide, LocationForSave, MovementCirclesRadiusList);
            RemakeInfoText(StatusEffects);
        }

        public void RemakeInfoText(List<StatusEffectDisplay> statuses)
        {
            if (InfoText == null)
            {
                InfoText = new BillboardTextVisual3D()
                {
                    Position = new Point3D(
                        CharImage.Origin.X, CharImage.Origin.Y + LongestPictureSide * 1.1,
                        CharImage.Origin.Z + PictureOffset + LongestPictureSide + 3),
                    FontSize = 18,
                    Background= new SolidColorBrush(Colors.Wheat),
                };
            }

            InfoText.Text = Name;
            foreach (var cur in statuses)
            {
                InfoText.Text = InfoText.Text + "\n   " + cur.Description + " -- R:" + cur.TurnsRemaining;
            }
        }


        private CharacterImagePiece ImageToRectangle(String imageFile,  double longestEdge, Point3D location,
            List<int> movementCircleRadiusList)
        {
            ImageBrush frontBrush =  MaterialMaker.MakeImageMaterial(imageFile);
            Material frontMaterial = new DiffuseMaterial(frontBrush);
            PictureOffset = 3.5;
            double length, width, baseConeRadius;
            double origWidth= frontBrush.ImageSource.Width;
            double origLength = frontBrush.ImageSource.Height;
            //The base cone should be larger than the smallest side.
            if (origWidth > origLength)
            {
                width = longestEdge;
                length = longestEdge / (origWidth / origLength);
                baseConeRadius = length / 1.3; 
            }
            else
            {
                width = (origWidth / origLength) * longestEdge;
                length = longestEdge;
                baseConeRadius = width / 1.3;
            }

            CharacterImagePiece charPic = new CharacterImagePiece()
            {
                Material = frontMaterial,
                BackMaterial = MaterialMaker.PaperbackMaterial(),
                Length = length,
                Width = width,
                Origin = new Point3D(location.X, location.Y, PictureOffset),
                Normal = new Vector3D(0.00001, 0.00001, 1),
                LengthDirection = new Vector3D(0, -.5, .5),
            };

            BaseConeRadius = longestEdge / 3;
            BaseCone = new TruncatedConeVisual3D()
            {
                Height = PictureOffset-1,
                BaseRadius = BaseConeRadius,
                TopRadius = BaseConeRadius,
                Material = new DiffuseMaterial(new SolidColorBrush(PieceColor)),
                Origin = new Point3D(location.X, location.Y, 0),
            };
            for(int curIndex = 0;curIndex<movementCircleRadiusList.Count;curIndex++)
            {
                var curCircleSize = movementCircleRadiusList[curIndex];

                MovementCircles.Add(
                    MakeMovementCircle(Speed, curCircleSize, location, PieceColor)
                    );
            }
            return charPic;

        }
        internal static Visual3D MakeMovementCircle(double speed, int curCircleSize, Point3D center, Color circleColor)
        {
            var allPoints = Helper3DCalcs.CirclePoints(speed*curCircleSize, center, 4);
            TubeVisual3D newMovementCircle = new TubeVisual3D();
            newMovementCircle.Path = new Point3DCollection(allPoints);
            newMovementCircle.Material = MaterialMaker.MaterialFromColor(circleColor);
            newMovementCircle.ThetaDiv = 18;
            return newMovementCircle;
        }


        internal void MoveTo(Point3D point3D)
        {
            double originalZ = Math.Round(point3D.Z, 4);
            var imageLocation = new Point3D(point3D.X, point3D.Y, originalZ + PictureOffset);
            LocationForSave = imageLocation;
            Point3DAnimation moveAnimationPic =
                new Point3DAnimation(CharImage.Origin, imageLocation, 
                    new Duration(new TimeSpan(0, 0, 0, 1)));
            Point3DAnimation moveAnimationCone = 
                new Point3DAnimation(BaseCone.Origin,
                    new Point3D(point3D.X, point3D.Y, originalZ), 
                    new Duration(new TimeSpan(0, 0, 0, 1)));
            Point3DAnimation textAnimation = new Point3DAnimation(InfoText.Position, new Point3D(point3D.X, point3D.Y + LongestPictureSide * 1.1, InfoText.Position.Z), new Duration(new TimeSpan(0, 0, 0, 1)));
            AnimationClock clock1 = moveAnimationPic.CreateClock();
            AnimationClock clock2 = moveAnimationCone.CreateClock();
            AnimationClock clock3 = textAnimation.CreateClock();
            CharImage.ApplyAnimationClock(CharacterImagePiece.OriginProperty, clock1);
            BaseCone.ApplyAnimationClock(TruncatedConeVisual3D.OriginProperty, clock2);
            InfoText.ApplyAnimationClock(BillboardTextVisual3D.PositionProperty, clock3);
            //CharImage.Origin = point1;
            //BaseCone.Origin = ;
        }



        internal void StopActive()
        {
            if (activeAnimation != null)
            {
                BaseCone.ApplyAnimationClock(TruncatedConeVisual3D.TopRadiusProperty, null);
                BaseCone.ApplyAnimationClock(TruncatedConeVisual3D.BaseRadiusProperty, null);
            }
        }
        public Visual3D AltThing;
        DoubleAnimation activeAnimation = null;
        internal void StartActive(bool onlyOneSelected)
        {
            //Hack to dumb this out for now
            onlyOneSelected = false;
            double radSize = 2.5;
            if (!onlyOneSelected)
            {
                radSize = 1.5;
            }
            activeAnimation = new DoubleAnimation(BaseConeRadius, BaseConeRadius * radSize, new Duration(new TimeSpan(0, 0, 0, 0, 800)));
            if (onlyOneSelected)
            {
                activeAnimation = new DoubleAnimation(BaseConeRadius, BaseConeRadius 
                    * 2.5, new Duration(new TimeSpan(0, 0, 0, 0, 800)));
                activeAnimation.AutoReverse = true;
                activeAnimation.RepeatBehavior = RepeatBehavior.Forever;
                
            }
            else
            {
                activeAnimation.AutoReverse = false;
            }
            AnimationClock _activeClock = activeAnimation.CreateClock();
            BaseCone.ApplyAnimationClock(TruncatedConeVisual3D.TopRadiusProperty, _activeClock);
            BaseCone.ApplyAnimationClock(TruncatedConeVisual3D.BaseRadiusProperty, _activeClock);
            for(int curIndex =0;curIndex < MovementCirclesRadiusList.Count;curIndex++)
            {
                var curMod = MovementCirclesRadiusList[curIndex];
                var curTube = MovementCircles[curIndex] as TubeVisual3D;
                curTube.Path = new Point3DCollection(Helper3DCalcs.CirclePoints(Speed*curMod, Location, 10));

            }
        }

        

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }
        #endregion

    }
}
